﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using PluginFramework.Client;
using CavemanTools.Lists;

namespace PluginFramework.Plugins
{
	/// <summary>
	/// Handles plugin settings
	/// </summary>
	public class PluginsStateManager
	{
		private IPluginRepository _repository;

		internal PluginsStateManager(IPluginRepository repository)
		{
			_repository = repository;			
		}

		/// <summary>
		/// Used by MEF
		/// </summary>
		[ImportMany]
		public Lazy<IPluginPart, IPluginMeta>[] Parts { get; set; }

		/// <summary>
		/// Returns plugins information from active packages.
		/// </summary>
		/// <returns></returns>
		public IEnumerable<PluginStatus> GetAvailablePlugins()
		{
			var all = Parts.Where(p => !_removed.Contains(p.Metadata.Package)).Select(p => p.Metadata);

			return all.Select(p => new PluginStatus() { PluginInfo = p, IsActive = ActivePlugins.Contains(p.Id) });
		}

		private IList<string> _enabled;
		private IList<string> ActivePlugins
		{
			get
			{
				if (_enabled == null) _enabled = _repository.GetActivePlugins();
				return _enabled;
			}
		}

		/// <summary>
		/// Plugins from removed packages are not created.
		/// </summary>
		/// <typeparam name="T">PluginType</typeparam>
		/// <param name="id">plugin id</param>
		/// <returns></returns>
		public T CreateInstance<T>(string id) where T : IPluginPart
		{
			var part = Parts.FirstOrDefault(d => d.Metadata.Id == id && !_removed.Contains(d.Metadata.Package));
			if (part == null) return default(T);
			return (T)part.Value;
		}

		/// <summary>
		/// Use it when you want to save the active/inactive state of plugins
		/// </summary>
		/// <param name="plugins"></param>
		public void UpdateState(IEnumerable<PluginStateUpdater> plugins)
		{
			if (plugins.IsNullOrEmpty()) return;
			_repository.UpdatePluginsState(plugins.Where(d => d.IsActive).Select(d => d.Id));
			
			if (OnDisablePlugins != null)
			{
				OnDisablePlugins(plugins.Where(d => !d.IsActive).Select(d => d.Id));
			}
		}


		List<string> _removed=new List<string>(2);
		
		/// <summary>
		/// All the plugins contained in the package are invisible
		/// </summary>
		/// <param name="package">package name</param>
		internal void MarkAsRemoved(string package)
		{
			if (Parts.Any(d=>d.Metadata.Package==package))_removed.Add(package);
		}

		protected IEnumerable<Lazy<IPluginPart,IPluginMeta>> RemovedPlugins
		{
			get { return Parts.Where(p => _removed.Contains(p.Metadata.Id)); }
		}

		/// <summary>
		/// Plugins from removed packages are deleted from repository
		/// </summary>
		internal void UpdateRemovedPlugins()
		{
			_repository.UpdatePluginsState(RemovedPlugins.Select(p=>p.Metadata.Id));
			if (OnDisablePlugins != null)
			{
				OnDisablePlugins(RemovedPlugins.Select(d => d.Metadata.Id));
			}
		}

		public event Action<IEnumerable<string>>  OnDisablePlugins;
	}
}